
// 3D WebGL, 3D Canvas and extended with 2D DIV Sprites THREE.JS implementation
// requires ThreeSpriteRenderer.js

// generic variables for rendering the 3D scene
var camera, scene, renderer, geometry, material, mesh;

// global model vars
var anglermodel; // shows the selected vector-angle

var coopyData = {
      models : [
          { etype :  2, spriteargs : { bgpos : {x :    0, y :    0 }, size :  40, rotations : 8}, loader : "JSON",   resource : ["","./3d/ship1_low.js","./3d/ship1.js"], scale : 0.2
        },{ etype :  3, spriteargs : { bgpos : {x :  -80, y : -120 }, size :  80, rotations : 1}, loader : "JSON",   resource : ["","./3d/starbase.js","./3d/starbase.js"], scale : 0.5
        },{ etype :  4, spriteargs : { bgpos : {x :    0, y : -200 }, size :  80, rotations : 1}, loader : "Sphere", resource : [""], surfaceColor : 0x4444aa, scale : 0.20
        },{ etype :  5, spriteargs : { bgpos : {x :  -80, y : -200 }, size :  80, rotations : 1}, loader : "Sphere", resource : [""], surfaceColor : 0x555555, scale : 0.15
        },{ etype :  6, spriteargs : { bgpos : {x : -160, y : -200 }, size :  80, rotations : 1}, loader : "JSON",   resource : ["","./3d/sun.js","./3d/sun.js"], scale : 0.5
        },{ etype :  7, spriteargs : { bgpos : {x : -240, y : -200 }, size : 160, rotations : 1}, loader : "Sphere", resource : [""], surfaceColor : 0x00000,  scale : 0.4
        },{ etype : 10, spriteargs : { bgpos : {x :    0, y : -400 }, size :  20, rotations : 8}, loader : "JSON",   resource : ["","./3d/photon.js","./3d/photon.js"], scale : 0.20
        },{ etype : 11, spriteargs : { bgpos : {x :    0, y :  -80 }, size :  40, rotations : 8}, loader : "JSON",   resource : ["","./3d/klingon_low.js","./3d/klingon.js"], scale : 0.4
        },{ etype :  21, spriteargs : { bgpos : {x :    0, y :    0 }, size :  40, rotations : 8}, loader : "JSON",   resource : ["","./3d/ship1_low.js","./3d/ship1.js"], scale : 0.2
        }],
      getModelByEtype : function ( etype ) {
           var i;
           for (i in this.models) {
               if (this.models[i].etype==etype) {
                   return i;
               }
           }
      },
      load : function () {

        function loadJSON (m) {
            var loader = new THREE.JSONLoader();
            loader.load(m.resource[renderMode], function ( geo ) {
                m.geo = geo;
                m.material = new THREE.MeshFaceMaterial();
                m.hasLoaded = true;
            } );

        }

        var i=0, m = {};
        for (i in this.models) {
            if (i) {
                m = this.models[i];
                if (renderMode>0) {
                    switch (m.loader) {
                      case "JSON":
                         loadJSON (m);
                         break;
                      case "Sphere":
                         m.geo = new THREE.SphereGeometry( 4, 8, 8 ),
                         m.material = new THREE.MeshBasicMaterial( { color: m.surfaceColor } );
                         m.hasLoaded = true;
                         break;
                    }
                } else {
                    m.hasLoaded = true;
                }
            }
        }
      } // load
    }


function getCoopyModel (coopyEntity, x,z,r) {

    coopyEntity.onStage = false;
    if (coopyEntity.etype==2 && renderMode>0) {
       anglermodel.position.x = x+0.5;
       anglermodel.position.z = z+0.5;
       anglermodel.rotation.y = r; // SINGLE PLAYER - dirty implementation
     }
     var i = coopyData.getModelByEtype(coopyEntity.etype);
     var m = coopyData.models[i];
     if (m) {
         if (m.hasLoaded) {
             if (renderMode > 0) {
                 coopyEntity.model = new THREE.Mesh(m.geo, m.material);
             } else {
                 coopyEntity.model = new THREE.DivSprite( m.spriteargs );
             }
             coopyEntity.model.scale.x = coopyEntity.model.scale.y = coopyEntity.model.scale.z = m.scale;
             coopyEntity.model.position.x = x+0.5;
             coopyEntity.model.position.z = z+0.5;
             coopyEntity.model.position.y = 0.5;
             coopyEntity.model.rotation.y = r;
             coopyEntity.hasLoaded = true;
         }
     }
}

function renderInit(div_element, renderMode) {

    scene = new THREE.Scene();

    camera = new THREE.OrthographicCamera(
           -15,//div_element.style.width / - 2,
           15,//div_element.style.width / 2,
           10,//div_element.style.height / 2,
           -10,//div_element.style.height / - 2,
           -2000, 1000 );   // width / height = 2 (viewport is set up as such
    //camera = new THREE.PerspectiveCamera( 90, 2 , 1, 2000 );
    camera.position.x = -2;
    camera.position.y = 1.5;
    camera.position.z = 2;
    scene.add( camera );
    
    if (renderMode > 0) {
        
        // Grid
        var line_material = new THREE.LineBasicMaterial( { color: 0xcccccc, opacity: 0.1 } ),
            geometry = new THREE.Geometry(),
            floor = -0.04, hsize = 10; vsize = 10; vscale = 1; hscale = 1;
    
        // vertical lines
        for ( var i = -hsize; i <= hsize; i ++ ) {
    
            geometry.vertices.push( new THREE.Vertex( new THREE.Vector3( - vsize, floor, i * hscale ) ) );
            geometry.vertices.push( new THREE.Vertex( new THREE.Vector3(   vsize, floor, i * hscale ) ) );
            geometry.vertices.push( new THREE.Vertex( new THREE.Vector3(   vsize, floor, (i+1) * hscale ) ) );
            geometry.vertices.push( new THREE.Vertex( new THREE.Vector3( - vsize, floor, (i+1) * hscale ) ) );
    
        }
    
        for ( var i = -vsize; i <= vsize; i ++ ) {
            geometry.vertices.push( new THREE.Vertex( new THREE.Vector3( i * vscale, floor, -hsize ) ) );
            geometry.vertices.push( new THREE.Vertex( new THREE.Vector3( i * vscale, floor,  hsize ) ) );
            geometry.vertices.push( new THREE.Vertex( new THREE.Vector3( (i+1) * vscale, floor,  hsize ) ) );
            geometry.vertices.push( new THREE.Vertex( new THREE.Vector3( (i+1) * vscale, floor, -hsize ) ) );
        }
    
        var line = new THREE.Line( geometry, line_material, THREE.LinePieces );
        scene.add( line );

        // Lights
        scene.add( new THREE.AmbientLight( 0x8888cc ) );
    
        var directionalLight = new THREE.DirectionalLight(0xeeeeee );
        directionalLight.position.x = 3;
        directionalLight.position.y = 6;
        directionalLight.position.z = 0;
        directionalLight.position.normalize();
        scene.add( directionalLight );
        
        // Angler
        var loader = new THREE.JSONLoader();
        loader.load("./3d/angler.js", function ( geo ) {
          anglermodel = new THREE.Mesh( geo, new THREE.MeshFaceMaterial() );
          anglermodel.position.y = 0.0;
          anglermodel.scale.x = anglermodel.scale.y = anglermodel.scale.z = 0.75;
          scene.add(anglermodel);
        });
        camera.lookAt( scene.position );
    
        if (renderMode >1) {
            renderer = new THREE.WebGLRenderer();
            if (!renderer.context) {
               renderer = new THREE.CanvasRenderer();
            }
        } else {
            renderer = new THREE.CanvasRenderer();
        };
    } else {
        renderer = new THREE.DivSpriteRenderer();
    };
    renderer.setSize( drawscale*20, drawscale*20 );
    div_element.appendChild( renderer.domElement );

}

function animate() {
    requestAnimationFrame( animate );
    render();
}

function render() {
    var timer;
    if (state.entities) {
        for (i=0;i<state.entities.length;i++) {
            e = state.entities[i];
            if (e.hasLoaded) {
                if (!e.onStage) {
                    scene.add(e.model);
                    if (renderMode==0) e.model.show(viewportdiv);      // would be better  not to reference the global variable
                    e.onStage = true;
                    createLabelDiv (e, viewportdiv);
                    var pos = e.model.toScreenXY();
                    e.labeldiv.style.top = Math.round(pos.y-10)+"px";
                    e.labeldiv.style.left = Math.round(pos.x)+"px";
                }
                if ( e.animate || false ) {
                    timer = Date.now();
                    l = 1.0*(timer-e.astart)/(e.duration);
                    if (l >= 1.0) {
                        e.animate = false;
                        e.ry += e.dry;
                        e.model.rotation.y = viewportdiv.orientation.rotation*e.ry;
                        e.x += e.dx;
                        e.y += e.dy;
                        e.model.position.x = e.x-viewportdiv.orientation.x+0.5;
                        e.model.position.z = e.y-viewportdiv.orientation.y+0.5;
                    } else {
                        e.model.position.x = e.dx*l + e.x-viewportdiv.orientation.x+0.5;
                        e.model.position.z = e.dy*l + e.y-viewportdiv.orientation.y+0.5;
                        e.model.rotation.y = viewportdiv.orientation.rotation*(e.dry*l + e.ry);
                    }
                    if (e.labeldiv || false) {
                        var pos = e.model.toScreenXY();
                        e.labeldiv.style.top = Math.round(pos.y)+"px";
                        e.labeldiv.style.left = Math.round(pos.x)+"px";
                    }
                }
                if ( e.etype == 3 ) {
                    e.model.rotation.y += 0.001;
                }
                if ( e.etype == 2 && renderMode>0) { // SINGLE PLAYER - dirty implementation of positioning the angler under the ship (won't work with multiplay
                    anglermodel.position.x = e.model.position.x;
                    anglermodel.position.z = e.model.position.z;
                }
            }
       }
    }
    renderer.render( scene, camera );
}

var createLabelDiv = function (entity) {
    
    entity.labeldiv = document.createElement("div");
    entity.labeldiv.className="label";
    entity.labeldiv.style.backgroundPosition=(entity.damage+"% 0px");
    entity.labeldiv.innerHTML = entity.elabel;
    viewportdiv.appendChild(entity.labeldiv);
}

var updateViewport = function(viewportdiv, debugdiv) {

    var debugHTML = "";
    for (i = 0;i<state.entities.length;i++) {
        debugHTML += state.entities[i].etype + ", ("+state.entities[i].x+","+state.entities[i].y+"), "+state.entities[i].angle+"; ";
        state.entities[i].model = new Object;
        getCoopyModel(state.entities[i], state.entities[i].x-viewportdiv.orientation.x,state.entities[i].y-viewportdiv.orientation.y, viewportdiv.orientation.rotation * state.entities[i].angle *  Math.PI / 180 );
    }
    debugdiv.innerHTML=debugHTML;
    animate();
}

var clearViewport = function () {
    var i;
    if (state.entities) {
        for (i = 0;i<state.entities.length;i++) {
            if (state.entities[i].model) {
                if (state.entities[i].hasLoaded) {
                    scene.remove(state.entities[i].model);
                    if (renderMode==0) state.entities[i].model.hide(viewportdiv);
                    state.entities[i].hasLoaded = false;
                    viewportdiv.removeChild(state.entities[i].labeldiv);
                }
            }
        }
    }
}

var start_animations = function(animationlist) {
    var getmodel = function (key) {
        var e = null;
        var i;
        if (state.entities) {
            for (i=0;i<state.entities.length;i++) {
                if (state.entities[i].key==key) {
                    e = state.entities[i];
                }
            }
        }
        return e;
    }

    var animdelay =0;
    var i;
    for (i = 0;i<animationlist.length;i++) {
            var anim = animationlist[i];
            var amodel = getmodel (anim.key);
            switch (anim.animationtype) {
                case "move":
                   if (amodel) {
                       amodel.dy = anim.y-amodel.y;
                       amodel.dx = anim.x-amodel.x;
                       var d_angle = (Math.abs(anim.angle-amodel.angle)>Math.abs(amodel.angle-anim.angle)) ? (amodel.angle-anim.angle) : (anim.angle-amodel.angle);
                       amodel.dry = d_angle * Math.PI / 180;
                       amodel.ry = amodel.angle * Math.PI / 180;
                       amodel.animate = true;
                       amodel.astart = Date.now();
                       amodel.duration = anim.duration+100;
                   }
                   break;
                case "damaged":
                   if (amodel) {
                       amodel.labeldiv.style.backgroundPosition=(anim.damage+"% 0px");
                   }
                   break;
                case "discard":
                   if (amodel) {
                      scene.remove(amodel.model);
                      if (renderMode==0) amodel.model.hide(viewportdiv);
                      amodel.hasLoaded = false;
                      viewport.removeChild(amodel.labeldiv);
                   }
            }
        }
}

var angler = function (angle) {
    if (renderMode>0) anglermodel.rotation.y = -angle/180*Math.PI;
}